<?php
/**
 * Класс обычных пользователей, данные для которых загруженны из БД.
 */
class Users_Model_User_Db extends Users_Model_User {
	const GET_BY_ARRAY = 4;

	/**
	 * @var boolean
	 */
	private static $_bSelectObjectMode = false;

	/**
	 * @var array
	 */
	protected static $_aFieldsMapGetBy = array(
		self::GET_BY_ID => 'id',
		self::GET_BY_LOGIN => 'login',
		self::GET_BY_EMAIL => 'email',
	);

	/**
	 * @var array
	 */
	protected static $_aNotSaveFields = array(
		'id',
		'created',
		'updated',
		'authorized',
		'created_ip',
		'authorized_ip',
	);

	/**
	 * @var array
	 */
	protected static $_aMainDbFields = array(
		'id','login','password','secret_word','email','status','rating',
		'first_name','last_name','patronymic','photo','message_by_email',
		'updated','authorized','authorized_ip','created','created_ip','avatar',
	);

	/**
	 * @var array
	 */
	protected static $_aFieldsMapDb = array(
	);

	/**
	 * Добавление нового пользователя.
	 * 
	 * @param array $aFields
	 * @return Users_Model_User_Db
	 */
	public static function addUser(array $aFields) {
		$aFields = array_merge(array(
			'created' => new Zend_Db_Expr('NOW()'),
			'created_ip' => Zend_Controller_Front::getInstance()->getRequest()->getClientIp(),
			'secret_word' => md5(microtime()),
		),$aFields);

		$oTable = new Users_Table_User();
		$iId = $oTable->insert($aFields);

		return self::getById($iId);
	}

	/**
	 * Получение количества строк для текущего фильтра.
	 * 
	 * @param array $aFilter
	 * @return integer
	 */
	public static function getCount($aFilter = array()) {
		self::$_bSelectObjectMode = true;
		$oSelect = self::getList($aFilter,array());
		$oTable = $oSelect->getTable();

		$oSelect->reset(Zend_Db_Select::COLUMNS);
		$oSelect->reset(Zend_Db_Select::FROM);
		$oSelect->from($oTable->getTableName(),array('CNT' => new Zend_Db_Expr('COUNT(*)')));

		$mResult = $oSelect->query()->fetch();
		return intval($mResult['CNT']);
	}

	/**
	 * Обработчик условий фильтрации.
	 * 
	 * @param string $sKey
	 * @param string $sRule
	 * @param mixed $mValue
	 * @return array
	 */
	public static function _callbackFilter($sKey,$sRule,$mValue) {
		switch (TRUE) {
			// Поля основной таблицы.
			case in_array($sKey,self::$_aMainDbFields):
				$mCond = is_array($mValue)
					? new Zend_Db_Expr($sKey.($sRule == '<>' ? ' NOT' : '').' IN ('.join(',',$mValue).")")
					: "$sKey $sRule ?";
				$mValue = is_array($mValue) ? null : $mValue;
				break;

			// Ошибка - неправильное название поля.
			default:
				throw new Zend_Exception("Wrong field name '$sKey' in \$aFilter argument (method ".__METHOD__.")");
		}

		return array($mCond,$mValue);
	}

	/**
	 * Получение списка пользователей.
	 *
	 * @param array $aFilter
	 * @param array $aOrder
	 * @param mixed $mLimit
	 * @return Users_Model_User_Db_List
	 */
	public static function getList($aFilter = array(), $aOrder = array('login' => 'asc'), $mLimit = 0) {
		// Выставление флага необходимости получения Zend_Db_Select объекта а не итератора.
		$bSelectObjectMode = self::$_bSelectObjectMode;
		self::$_bSelectObjectMode = false;

		// Получение Zend_Db_Select объекта с применёнными условиями фильтрации, сортировки и ограничения количества.
		$oSelect = self::_getList(
			new Users_Table_User(),
			$aFilter,
			$aOrder,
			$mLimit,
			array(__CLASS__,'_callbackFilter'),
			array('>status' => -1) // Не получаем удалённые записи.
		);

		// Если установлен режим получения объекта Zend_Db_Select.
		if ($bSelectObjectMode) {
			return $oSelect;
		}
		// Выполнение запроса и возращение объекта со списком результатов.
		else {
			$oList = new Users_Model_User_Db_List($oSelect->query()->fetchAll());
			$oList->setObjectClass(__CLASS__);
			return $oList;
		}
	}

	/**
	 * Создание объекта данного класса.
	 * 
	 * @param mixed $mIdentity
	 * @param integer $iGetBy
	 * @param boolean $bReadOnly
	 */
	public function __construct($mIdentity, $iGetBy = self::GET_BY_ARRAY, $bReadOnly = false) {
		parent::__construct($mIdentity, $iGetBy);
		$this->_bReadOnly = $bReadOnly;

		// Если инициализация происходит не из массива, то обращаемся к БД.
		if ($iGetBy != self::GET_BY_ARRAY) {
			$sFieldName = self::$_aFieldsMapGetBy[$iGetBy];
			$oUserTable = new Users_Table_User();

			if (!$oUserRow = $oUserTable->fetchRow(array("$sFieldName = ?" => $mIdentity))) {
				throw new Users_Model_Exception("Wrong user udentity $mIdentity");
			}

			$mIdentity = $oUserRow->toArray();
		}

		// Если необходимо, то проводим преобразование ключей массива.
		foreach ($mIdentity as $sFieldName => $mValue) {
			$sTarget = isset(self::$_aFieldsMapDb[$sFieldName])
				? self::$_aFieldsMapDb[$sFieldName]
				: $sFieldName;
			$this->_aFields[$sTarget] = $mValue;
		}

		// Если пользователь удалён, то объект доступен в режиме "только чтение".
		$this->_bReadOnly = $this->_bReadOnly || $this->_aFields['status'] < 0;
	}

	/**
	 * (non-PHPdoc)
	 * @see application/modules/users/models/Users_Model_User#save()
	 */
	public function save() {
		// Если есть изменения, то сохраняем их.
		if ($this->isChanged()) {
			$aFields = array();

			// Проходим по списку полей и подготавливаем их для сохранения в БД.
			foreach ($this->toArray() as $sField => $mValue) {
				// Отсеиваем поля, которые предназначенны только для чтения.
				if (false === array_search($sField,self::$_aNotSaveFields)) {
					// Проводим обратное преобразование ключей массива.
					if ($sKey = array_search($sField,self::$_aFieldsMapDb)) {
						$sField = $sKey;
					}

					$aFields[$sField] = $mValue;
				}
			}

			// Вносим изменения в БД.
			$oUserTable = new Users_Table_User();
			$iAffected = $oUserTable->update($aFields,array('id = ?' => $this->getId()));

			// Применяем изменения в объекте.
			if ($iAffected == 1) {
				$this->_aFields = array_merge($this->_aFields,$this->_aChanges);
				$this->_aChanges = array();
				return true;
			}
		}

		return false;
	}

	/**
	 * (non-PHPdoc)
	 * @see application/modules/users/models/Users_Model_User#delete()
	 */
	public function delete() {
		// Вносим изменения в БД.
		$oUserTable = new Users_Table_User();
		$aFields = array('status' => Users_Model_User::getUser()->getId() == $this->getId() ? -1 : -2);
		$iAffected = $oUserTable->update($aFields,array('id = ?' => $this->getId()));

		// Вносим изменения в объект.
		if ($bResult = $iAffected == 1) {
			$sKey = ($sKey = array_search('status',self::$_aFieldsMapDb)) ? $sKey : 'status';
			$this->_aFields[$sKey] = $aFields['status'];
			$this->_aChanges = array();
			$this->_bReadOnly = true;

			// Отправка письма с уведомлением об удалении.
			$oMailHelper = new Users_Helper_Mail();
			$oHttpUri = Zend_Controller_Action_HelperBroker::getStaticHelper('HttpUri');
			$oMailHelper->direct($this->getEMail(),'on_user_delete',array(
				'restore_time' => date('r',time() + 3600*24*90),
				'restore_url' => $oHttpUri->direct('/users/profile/restore?'.http_build_query(array(
					'id' => $this->getId(),
					'sign' => md5(join(':',array($this->getSecretWord(),$this->getId(),'restore-profile'))),
				))),
			));
		}

		return $bResult;
	}
}
?>